﻿using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Prayol.SSOClient.WebApi.Data;
using Prayol.SSOClient.WebApi.Data.Generated;
using Prayol.SSOClient.WebApi.Models;

namespace Prayol.SSOClient.WebApi.Services
{
    public class AuthService
    {
        private readonly OpenAuthDbContext _context;
        private readonly IMemoryCache _cache;

        public AuthService(OpenAuthDbContext context,IMemoryCache cache)
        {
            _context = context;
            _cache = cache;
        }

        public LoginResult Login(PassportLoginRequest request)
        {
            request.Trim();

            //todo:建立appInfo表 将信息存入数据库
            var user=_context.User.Single(c => c.Account == request.Account);
            if (user == null) throw new Exception("用户不存在");
            if(user.Password!=request.Password) throw new Exception("用户密码错误");

            var currentSession = new UserAuthSession
            {
                Account = user.Account,
                Name = user.Name,
                Token = Guid.NewGuid().ToString().GetHashCode().ToString("x"),
                AppKey = "beng",
                CreateTime = DateTime.Now,
                IpAddress = request.IpAddress
            };

            _cache.Set(currentSession.Token, currentSession, new TimeSpan(10,0,0,0));

            return new LoginResult(){ReturnUrl = "www.baidu.com",Token = currentSession.Token};
        }

        public void LoginOut(string token)
        {
            _cache.Remove(token);
        }

        public bool CheckToken(string token)
        {
            if (_cache.TryGetValue(token, out UserAuthSession _))
            {
                return true;
            }

            return false;
        }

        public UserAuthSession GetUserInfoByToken(string token)
        {
            return _cache.TryGetValue(token, out UserAuthSession userAuthSession) ? userAuthSession : null;
        }

        public UserWithAccessedCtrls GetAccessedControls(string  username)
        {
            var userWithAccessedCtrls = new UserWithAccessedCtrls()
            {
                User = _context.User.Single(c => c.Account == username),
            };
            var userId = userWithAccessedCtrls.User.Id;
            var roleIds = GetRoleIds(userId);

            var userDefines=new List<string>(){Define.USERORG,Define.USERMODULE,Define.USERRESOURCE,Define.USERELEMENT};
            var roleDefines =
                new List<string>() {Define.ROLEORG, Define.ROLEMODULE, Define.ROLEELEMENT, Define.ROLERESOURCE};
            var ids = _context.Relevance
                .Where(c => c.FirstId == userId && (userDefines.Contains(c.Key) || roleDefines.Contains(c.Key)))
                .Select(c => new {c.Key, Id = c.SecondId}).ToList();

            //角色
            userWithAccessedCtrls.Roles = _context.Role.Where(c => roleIds.Contains(c.Id)).ToList();

            //组织机构
            userWithAccessedCtrls.Orgs = _context.Org.Where(c => ids.Where(i=> i.Key==Define.USERORG|| i.Key==Define.ROLEORG).Select(i => c.Id).Contains(c.Id)).ToList();
            
            //模块以及模块元素
            var modules = _context.Module.Where(c => ids.Where(i => i.Key == Define.USERMODULE || i.Key == Define.ROLEMODULE).Select(i => c.Id).Contains(c.Id)).OrderBy(o => o.SortNo).ToList();
            userWithAccessedCtrls.Modules = new List<Module>();
            foreach (var module in modules)
            {
                module.Elements = _context.ModuleElement.Where(c => c.ModuleId == module.Id&& ids.Where(i => i.Key == Define.USERELEMENT || i.Key == Define.ROLEELEMENT).Select(i => c.Id).Contains(c.Id)).ToList();
                userWithAccessedCtrls.Modules.Add(module);
            }

            //资源
            userWithAccessedCtrls.Resources=_context.Resource.Where(c => ids.Where(i => i.Key == Define.USERRESOURCE || i.Key == Define.ROLERESOURCE).Select(i => c.Id).Contains(c.Id)).ToList();

            return userWithAccessedCtrls;
        }

        private List<string> GetRoleIds(string userId)
        {
            return _context.Relevance.Where(c => c.FirstId == userId && c.Key == Define.USERROLE)
                .Select(c => c.SecondId).ToList();
        }
    }
}